(function(global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('moment'), require('hy5b/frontend/jsonview')) :
    typeof define === 'function' && define.amd ? define(['moment', 'jsonview'], factory) :
    global.log = factory(moment, jsonview);
}(this, function(moment, jsonview) {

  var i = 10000;
  var last = 0;
  var first = true;

  function timestamp() {
    return moment().format('YYYY-MM-DD HH:mm:ss,SSSZ');
  }

  function tlog(type) {
    function ret() {}
    ret.valueOf = function() {
      var now = Date.now();
      var tag = '';
      if (first) {
        tag = i;
        first = false;
      } else {
        tag = i + '(+' + (now - last) + 'ms)';
      }
      i++;
      last = now;
      return [timestamp(), tag, '<' + type + '>'].join(' ');
    }
    return ret;
  }

  var log;
  if (console.log.bind) {
    log = console.log.bind(console, tlog('log'));
  } else {
    log = function() {
      console.log(Array.prototype.slice.call(arguments).join(', '));
    }
  }

  if (![].forEach) {
    Array.prototype.forEach = function(call) {
      for (var i = 0; i < this.length; i++) {
        call(this[i], i, this);
      }
    }
  }

  ['info', 'debug', 'warn', 'error'].forEach(function(type) {
    log[type] = console[type] && console[type].bind ? console[type].bind(console, tlog(type)) : console[type];
  });

  log.getLogger = function(elem) {
    var clog = function(elem) {
      if (!elem) {
        elem = document.createElement('div');
        document.body.appendChild(elem);
      }
      this.elem = elem;
    };
    ['info', 'debug', 'warn', 'error'].forEach(function(type) {
      clog.prototype[type] = function() {
        var childNodes = document.createElement('p');

        var child = document.createElement('span');
        child.style.marginRight = '2em';
        child.innerHTML = [timestamp(), '&lt;' + type + '&gt;'].join(' ');
        childNodes.appendChild(child);

        Array.prototype.slice.call(arguments).forEach(function(param) {
          child = document.createElement('span');
          child.innerHTML = jsonview(param);
          childNodes.appendChild(child);
        });
        this.elem.appendChild(childNodes);
        return this;
      }
    });
    return new clog(elem);
  }

  return log;

}))
